﻿#include <stdlib.h>
#include "LinkedList.h"

void throwError()
{
	perror("Out of index error\n");
	exit(1);
}

LinkedList* loadElement(LinkedList* _list, int pos)
{
	int i;
	LinkedList* current;
	if (pos > _list->value) throwError();
	else if (pos < 0) throwError();
	else if (pos == 0) return _list->prev;
	else if (pos == _list->value) return _list->next;
	else if ((_list->value - pos) < (_list->value / 2)) 
	{
		current = _list->next;
		for (i = 1; i < _list->value - pos; i++)
			current = current->prev;
		return current;
	}
	else
	{
		current = _list->prev;
		for (i = 0; i < pos; i++)
			current = current->next;
		return current;
	}
}

LinkedList* newList()
{
	LinkedList* _list = (LinkedList*)malloc(sizeof(LinkedList));
	_list->value = 0;
	return _list;
}

LIST_TYPE peekList(LinkedList* _list)
{
	return _list->next->value;
}

LIST_TYPE getFirst(LinkedList* _list)
{
	return _list->prev->value;
}

int listLength(LinkedList* _list)
{
	return _list->value;
}

LIST_TYPE getElement(LinkedList* _list, int pos)
{
	LinkedList* current = loadElement(_list, pos);
	return current->value;
}

void addFirst(LinkedList* _list, LIST_TYPE value)
{
	_list->next = (LinkedList*)malloc(sizeof(LinkedList));
	_list->prev = _list->next;
	_list->next->value = value;
	_list->value++;
	_list->next->prev = _list;
}

void addElement(LinkedList* _list, LIST_TYPE value)
{
	if (_list->value == 0)
	{
		addFirst(_list, value);

	}
	else
	{
		_list->next->next = (LinkedList*)malloc(sizeof(LinkedList));
		_list->next->next->value = value;
		_list->value++;
		_list->next->next->prev = _list->next;
		_list->next = _list->next->next;
	}
}

void appendToBegin(LinkedList* _list, LIST_TYPE value)
{
	if (_list->value == 0)
	{
		addFirst(_list, value);

	}
	else
	{
		LinkedList* first = _list->prev;
		_list->prev = (LinkedList*)malloc(sizeof(LinkedList));
		_list->prev->value = value;
		_list->prev->next = first;
		first->prev = _list->prev;
	}
}

void removeElement(LinkedList* _list, int pos)
{
	LinkedList* current = loadElement(_list, pos);
	current->prev->next = current->next;
	current->next->prev = current->prev;
	_list->value -= 1;
	free(current);
}

void removeList(LinkedList* _list)
{
	int i;
	LinkedList* current = _list->prev;
	for (i = 0; i < _list->value-1; i++)
	{
		current = current->next;
		free(current->prev);
	}
	free(current);
	free(_list);
}

LIST_TYPE* listToArray(LinkedList* _list)
{
	int i;
	LIST_TYPE* a = (LIST_TYPE*)calloc(_list->value, sizeof(LIST_TYPE));
	LinkedList* current = _list->prev;
	for (i = 0; i < _list->value - 1; i++)
	{
		current = current->next;
		a[i] = current->prev->value;
	}
	a[_list->value - 1] = current->value;
	return a;
}

void insertElement(LinkedList* _list, int pos, LIST_TYPE value)
{
	LinkedList* current = loadElement(_list, pos);
	LinkedList* next = current;
	LinkedList* prev = current->prev;
	prev->next =(LinkedList*)malloc(sizeof(LinkedList));
	current = prev->next;
	current->prev = prev;
	current->next = next;
	next->prev = current;
	prev->next = current;
	current->value = value;
	_list->value += 1;
}

LinkedList* arrayToList(LIST_TYPE* arr, int length)
{
	LinkedList* list = newList();
	int i;
	for (i = 0; i < length; i++)
	{
		addElement(list, arr[i]);
	}
	return list;
}

void appendList(LinkedList* _list, LIST_TYPE* arr, int length)
{
	int i;
	for (i = 0; i < length; i++)
	{
		addElement(_list, arr[i]);
	}
}

LinkedList* listSlice(LinkedList* _list, int start, int end)
{
	LinkedList* slice = newList();
	LinkedList* current = loadElement(_list, start);
	int i;
	if (end > _list->value) throwError();
	for (i = 0; i < end - start; i++)
	{
		addElement(slice, current->value);
		current = current->next;
	}
	return slice;
}

LinkedList* copyList(LinkedList* _list)
{
	LinkedList* copy = listSlice(_list, 0, _list->value);
	return copy;
}

void listCat(LinkedList* dst, LinkedList* src)
{
	int i;
	LinkedList* current = src->prev;
	for (int i = 0; i < src->value - 1; i++)
	{
		addElement(dst, current->value);
		current = current->next;
	}
	addElement(dst, current->value);
}